QS_ListView=function(container,columns,config,callback){
    this.container=container;
    this.callback=callback||{};
    this.columns=columns;
    this.config={
        gConfig:{
            column:this.columns,
            indexColKey:'gkey',
            autoWidth: true,
            lazyLoad: false,
            sortable: true,
            cellResize: false,
            cellRearrange: false,
            alternateRow: false,
            autoHeight:true
        },
        title:'Title',
        hideTitle:false
    };
    if(config){
        $.extend(true,this.config,config);
    }
    this.el=null;
    this.html='<div class="qs-listview">'+(this.config.hideTitle?'':'<div class="qs-listview-hd">'+this.config.title+'</div>')+'<div class="qs-listview-bd"></div></div>';
    this.grid=null;
    this.contentKey = document.body.textContent ? 'textContent' : 'innerText';
    this.init();
};
QS_ListView.prototype={
    init:function(){
        this.el=$(this.html).appendTo(this.container);
        this._createGrid();
    },
    _createGrid:function(){
        this.grid=new Util.DataGrid(this.el.find('.qs-listview-bd'),null,this.config.gConfig,this.callback);
    },
    reBindData:function(data){
        this.grid.reBindData(data);
    },
    getDOMMap:function(){
        return this.grid.DOMMap;
    },
    getIDs:function(){
        return this.grid.getIDs();
    },
    setDataToRow:function(key,data){
        if (this.grid.rows[key]) {
            $.extend(this.grid.rows[key].data, data);
        }
    },
    highlightColumn:function(dataIndex){
        this.grid.highlightColumn(dataIndex, true);
        var headCells=this.grid.header.row.cells;
        for(var c in headCells){
            if(c==dataIndex){
                this.grid.header.row.cells[c].el.addClass('rtq-grid-cell-highlight');
            }else{
                this.grid.header.row.cells[c].el.removeClass('rtq-grid-cell-highlight');
                this.grid.header.row.cells[c].el.removeClass('rtq-grid-cell-highlight');
            }
        }
    },
    updateData:function(key,aData){
        if(!this.grid.DOMMap[key]){
            return;
        }
        var gValue,oValue;
        if(aData["Chg"]){
            aData["UpDown"]=aData["Chg"];
        }
        for (var field in aData) {
            if (!aData.hasOwnProperty(field)||!aData[field]) {
                continue;
            }
            gValue = aData[field].value;
            oValue = aData[field].oValue;
            if (typeof gValue != 'undefined' && gValue != null) {
                this.updateDOM(key, field, gValue, oValue);
            }
        }
    },
    updateDOM:function(key, field, data, oldData){
        var contentKey=this.contentKey;
        var el = this.grid.DOMMap[key]?this.grid.DOMMap[key][field]:null;
        if(!el){
            return;
        }
        var ellipsis=false;
        switch (field) {
            case 'LastPrice':
               data = data.toFixed(3);
               flash(el,null,null);
               break;
            case 'UpDown':
                contentKey='innerHTML';
                var cls = data >= 0 ? "up" : "down";
                data = '<a class="updown ' + cls + '" href="javascript:void(0)">' + cls + '</a>';
                break;
            case 'Chg':
            case 'Chg%':
                var d = data;
                data=data.toFixed(3);
                flashWithDirectional(el,data,oldData,d>=0)
                break;
            case 'HighPrice':
            case 'LowPrice':
                data = data.toFixed(3);
                break;
            case 'Volume':
                data = data / 1000000;
                data = data.toFixed(3);
                flash(el,null,null);
                break;
            case 'Name':
                ellipsis=true;
                contentKey='innerHTML';
                data='<a href="javascript:void(0)" title="'+data+'" style="overflow:hidden;">'+data+'</a>';
                break;
            default:
                break;
        }
        if (!ellipsis) {
            el[contentKey] = data;
        }else{
            this.grid.rows[key].cells[field].updateCell(data);
        }
//      if(field=='Name'){
//          $(el).find('a').ellipsis();
//      }
    },
    clear:function(){
        for(var p in this){
            if(!p || p == 'clear'){continue;}
            this[p] = null;
            delete this[p];
        }
    },
    empty:function(){
        this.grid.empty();
    }
};
QS_BaseGainerLoserActive={
    html:'<div class="qs-gla"><div class="hd clearfix"></div><div class="bd"><div class="data clearfix"></div></div></div>',
    listViews:{},
    customColumns:[{
        header: "gkey",
        dataIndex: 'gkey',
        hide: true
    }, {
        header: "Name",
        dataIndex: 'Name',
        width: '33%',
        align: 'left'
    }, {
        header: '<span style="display:none;">Up/Down</span>',
        dataIndex: 'UpDown',
        width: '5%',
        className: 'column-updown',
        align: 'center'
    }, {
        header: "Last",
        dataIndex: 'LastPrice',
        width: '10%',
        className: 'column-lastprice',
        align: 'right',
        dataType: 'float'
    }, {
        header: "Chg",
        dataIndex: 'Chg',
        width: '10%',
        align: 'right',
        className: 'column-chg',
        dataType: 'float'
    }, {
        header: "Chg %",
        dataIndex: 'Chg%',
        className: 'column-chgpc',
        width: '10%',
        align: 'right',
        dataType: 'float'
    }, {
        header: "High",
        dataIndex: 'HighPrice',
        className: 'column-high',
        width: '10%',
        align: 'right',
        dataType: 'float'
    }, {
        header: "Low",
        dataIndex: 'LowPrice',
        className: 'column-low',
        width: '10%',
        align: 'right',
        dataType: 'float'
    }, {
        header: "Volume(mil)",
        dataIndex: 'Volume',
        className: 'column-volumn',
        width: '12%',
        align: 'right',
        dataType: 'float'
    }],
    
    MSTATSTickerMap:{
        126:'MSTATS_ALL_MJ',
        127:'MSTATS_ALL_MJ',
        1:'MSTATS_AMX_L_MJ',
        14:'MSTATS_NYS_L_MJ',
        16:'MSTATS_ARC_L_MJ',
        19:'MSTATS_NAS_L_MJ',
        127.1:'MSTATS_TSX_MJ',
        127.2:'MSTATS_VEN'
    },
    
    visibleTokens:[],
    
    countryMap:{126:'USA',127:'Canada'},
    
    //exchMapping:{'XTSX':'TSXV','XTSE':'TSX','XNYS':'NYSE','XASE':'AMEX','ARCA':'ARCA','XNAS':'NASDAQ','XPSE':'PSE','OOTC':'OOTC'},
    //staticTicker:"MSTATS_ALL_MJ",
    //staticTickerMap:{1:'MSTATS_AMX_L_MJ',14:'MSTATS_NYS_L_MJ',16:'MSTATS_ARC_L_MJ',19:'MSTATS_NAS_L_MJ',127:'MSTATS_TSX_MJ','127_1':'MSTATS_VEN'},
    //selectExchCode:[127,126],
    //MICMap:{143:'XSES',136:'XSHG',127:'XTSE'},
    tokens:{D1902:'% Gainers',D1900:'Net Gainers',D1903:'% Losers',D1901:'Net Losers',D1904:'Most Actives'},
    //countryMap:{126:'USA',127:'Canada'},
    mainTickers:{},
    subTickers:{},
    mainIntervalObj:null,
    mianIntervalTime:60000,
    config:{
        maxCount:10,
        needReplaceExternalSymbol:false,
        quoteURL:'getGLAQuoteData1.jsp',
        instid:'quest',
        //showHead:false,
        width:0,
        height:0,
        fixHeight:true,
        clickable:true
    },
    callback:{},
    loaded:false,
    lastCallbackHeight:0,
    _getExternalSymbol:function(symbols,callback){
        checkTickerInfo(symbols,function(data){
            if ((!data || !data.Records || data.Records.length < 1)) return;
            var sybmolmap={};
            var rs, lg = data.Records.length,tenforeCode,tenforeTicker;
            for (var i = 0; i < lg; i++) {
               rs = data.Records[i];
               if(rs.ClientTicker&&rs.QueryKey&&rs.TenforeInfo){
                     tenforeCode=  rs.TenforeInfo[1]; 
                     tenforeTicker =  rs.TenforeInfo[0];
                    if (tenforeCode&&tenforeTicker) {
                        tenforeCode=tenforeCode<126?126:tenforeCode;
                        sybmolmap[tenforeCode + ":" +tenforeTicker] = {
                            ticker: rs.ClientTicker,
                            name: rs.Name || ''
                        }
                    }
               }
            }
            callback(sybmolmap);
        })
    },
    _forceUpdateData:function(listView){
        var ids=listView.getIDs(),gkey,d,oData;
        for(var i=0,l=ids.length;i<l;i++){
            gkey=ids[i];
            d=this.subTickers[gkey];
            if(d){
                oData={
                    LastPrice:{
                        value:d["LastPrice"],
                        oVlaue:null,
                        dataType:'f'
                    },
                    Chg:{
                        value:d["Chg"],
                        oVlaue:null,
                        dataType:'f'
                    },
                    Volume:{
                        value:d["Volume"],
                        oVlaue:null,
                        dataType:'f'
                    },
                    HighPrice:{
                        value:d["HighPrice"],
                        oVlaue:null,
                        dataType:'f'
                    },
                    LowPrice:{
                        value:d["LowPrice"],
                        oVlaue:null,
                        dataType:'f'
                    },
                    Name:{
                        value:d["Name"],
                        oVlaue:null,
                        dataType:'s'
                    }
                };
                oData["Chg%"]={
                    value:d["Chg%"],
                    oVlaue:null,
                    dataType:'f'
                };
                listView.updateData(gkey,oData);
            }else{
                continue;
            }
        }
    },
    _mainCallback:function(o){
        window.GLAData = {
            main: this.mainTickers,
            sub: this.subTickers
        };
        var self=this;
        var items=o.items,needSubTciekrs=[],needSearchExSymbol=[];
        if(items&&items.length>0){
            var exch,gkey,fields,symbol;
            for(i=0,l=items.length;i<l;i++){
                symbol=items[i].symbol;
                exch=items[i].service;
                gkey=exch+":"+symbol.split("|")[1];
                if(!this.mainTickers[gkey]){
                    this.mainTickers[gkey]={};
                }
                exch=this.genExchange(exch);//quote data from 126 composive exchange
                fields=items[i].fields;
                var fieldName,fieldValue,token,gridData;
                if(fields.length>0){
                    for(var j=0,jl=fields.length;j<jl;j++){
                        gridData=[];
                        fieldName=fields[j].name;
                        fieldValue=fields[j].value;
                        if((fieldName=='D1900'||fieldName=='D1901'||fieldName=='D1902'||fieldName=='D1903'||fieldName=='D1904')&&$.inArray(fieldName,this.visibleTokens)>-1){
                            token=fieldName;
                            var oldFieldValue=this.mainTickers[gkey][fieldName];
                            if(oldFieldValue==fieldValue){
                                continue;
                            }
                            var subTickers=fieldValue.split(",");
                            var subKey;
                            var len=subTickers.length>this.config.maxCount?this.config.maxCount:subTickers.length;

                            if (oldSubTickers) {
                                 var oSubKey,oldSubTickers=oldFieldValue.split(",");
                                for (var m = 0; m < len; m++) {// delete old tickers
                                   oSubKey=exch+":"+oldSubTickers[m];
                                    delete this.subTickers[oSubKey]['tokens'][token];//delete old grid 
                                    if ($.isEmptyObject(this.subTickers[oSubKey]['tokens'])) {
                                        delete this.subTickers[oSubKey];
                                    }
                                }
                            }
                            
                            for(var k=0;k<len;k++){
                                subKey=exch+":"+subTickers[k];
                                var pullkey=exch + ".1." + subTickers[k];
                                if ($.inArray(pullkey, needSubTciekrs) < 0) {// remove duplicate subticker
                                    needSubTciekrs.push(pullkey);
                                }
                                if(!this.subTickers[subKey]){// subscribe new ticker
                                    this.subTickers[subKey]={};
                                }
                                
                                if(!this.subTickers[subKey]['tokens']){
                                    this.subTickers[subKey]['tokens']={};
                                }
                                if(!this.subTickers[subKey]['tokens'][token]){
                                    this.subTickers[subKey]['tokens'][token]=1;
                                }
                                gridData.push({
                                    gkey:subKey,
                                    Symbol:subTickers[k],
                                    Name:this.subTickers[subKey].Name||''
                                });
                            }
                            this.mainTickers[gkey][fieldName]=fieldValue;
                            if (this.listViews[exch][token]) {
                                this.listViews[exch][token].reBindData(gridData);
                                this._forceUpdateData(this.listViews[exch][token]);
                            }
                        }else{
                            continue;
                        }
                    }
                }
            }
        }
        if (needSubTciekrs.length>0) {
            var para={
                tickers:needSubTciekrs.join(",")
            };
            this._quoteTickers(para, function(body){
                self._subCallback(body);
                self._replaceClientSymbol();
            });
        }
    },
    _subCallback:function(o){
        var items=o.items;
        if(!$.isArray(items)) return;
        for(var i=0,l=items.length;i<l;i++){
            var needUpdateField={};
            var symbol=items[i].symbol;
            var service=items[i].service;
            var fields=items[i].fields;
            var gkey=service+":"+symbol.split("|")[1];  
            var subTicker=this.subTickers[gkey];
            if(!subTicker){
                continue;
            }
            for(var j=0,jl=fields.length;j<jl;j++){
                var fieldName=fields[j].name;
                var oldValue=subTicker[fieldName];
                var value=fields[j].value;
                var ty='s';
                if (fieldName == "LastPrice" || fieldName == "ClosePrice" || fieldName == "AfterTPrice" || fieldName == "Volume"||fieldName == "HighPrice"||fieldName == "LowPrice") {
                    value = parseFloat(value,10);
                    ty='f';
                }else if(fieldName == "AfterTDate" ||fieldName == "TradeDate"){
                    value=formatDateString(value);
                    ty='s';
                }else if(fieldName == "AfterTTime" ||fieldName == "TradeTime"){
                    value = parseInt(value, 10);
                    ty='i';
                }else if(fieldName == "Name"){
                    value = formatNameString(value);
                }
                if(oldValue!=value){
                    needUpdateField[fieldName]={
                        value:value,
                        oValue:oldValue,
                        dataType:ty
                    };
                    subTicker[fieldName]=value;
                }
            }
            var chg,chgp;
            if(!this._isAfter(subTicker['AfterTDate'],subTicker['AfterTTime'],subTicker['TradeDate'],subTicker['TradeTime'])){
                if(subTicker['LastPrice']>0&&subTicker['ClosePrice']>0&&(needUpdateField['LastPrice']||needUpdateField['ClosePrice'])){
                    chg=subTicker['LastPrice']-subTicker['ClosePrice'];
                    chgp=chg/subTicker['ClosePrice']*100;
                    if(chg!=subTicker['Chg']){
                        needUpdateField['Chg']={
                            value:chg,
                            oValue:subTicker['Chg'],
                            dataType:'f'
                        };
                        needUpdateField['Chg%']={
                            value:chgp,
                            oValue:subTicker['Chg%'],
                            dataType:'f'
                        };
                        subTicker['Chg%']=chgp;
                        subTicker['Chg']=chg;
                    }
                }
            }else{
                if(subTicker['AfterTPrice']>0&&subTicker['LastPrice']>0&&(needUpdateField['AfterTPrice']||needUpdateField['LastPrice'])){
                    chg=subTicker['AfterTPrice']-subTicker['LastPrice'];
                    chgp=chg/subTicker['LastPrice']*100;
                    if(chg!=subTicker['Chg']){
                        needUpdateField['Chg']={
                            value:chg,
                            oValue:subTicker['Chg'],
                            dataType:'f'
                        };
                        needUpdateField['Chg%']={
                            value:chgp,
                            oValue:subTicker['Chg%'],
                            dataType:'f'
                        };
                        subTicker['Chg%']=chgp;
                        subTicker['Chg']=chg;
                    }
                }
            } 
            for(var token in subTicker.tokens){
                for(var exch in this.listViews){
                    if(!this.listViews[exch][token]){
                        continue;
                    }
                    if(!subTicker['Gid']){// add the style for invalid symbol
                        var DOMMap=this.listViews[exch][token].getDOMMap();
                        if(DOMMap[gkey]){
                            $(DOMMap[gkey]['Symbol']).parent('.column-symbol').addClass('column-invalid');
                            $(DOMMap[gkey]['Name']).parent('.column-name').addClass('column-invalid');
                        }
                    }
                    if (!$.isEmptyObject(needUpdateField)) {
                        this.listViews[exch][token].updateData(gkey, needUpdateField);
                    }
                }
            }
        }
        if(!this.loaded){
            this.changeOutSize(this.config.width,this.config.height);
        }
    },
    _replaceClientSymbol:function(){
        var self=this;
        if(!this.config.needReplaceExternalSymbol){
            return;
        }
        var tickers=[],subTicker;
        for(var gkey in this.subTickers){
            subTicker=this.subTickers[gkey];
            if(!subTicker.replaced&&subTicker['Gid']){
                tickers.push(subTicker['Gid']);
            }
        }
        if(tickers.length>0){
            this._getExternalSymbol(tickers,function(o){
                //console.log(o);
                for(var k in self.subTickers){
                    self.subTickers[k].replaced=true;
                    if(o[k]){
                        self.subTickers[k].ClientTicker=o[k].ticker;
                        self.subTickers[k].Name=o[k].name;
                        for (var exch in self.listViews) {
                            for (var t in self.tokens) {
                                if (self.subTickers[k]["tokens"][t] == 1) {
                                    self.listViews[exch][t].updateData(k, {
                                        Symbol: {
                                            value: o[k].ticker,
                                            dataType: 's',
                                            oVlaue: null
                                        }
                                    })
                                }
                            }
                        }
                    }
                }
            });
        }
    },
    _isAfter:function(ad,at,td,tt){
        if(!ad||!at){
            return false;
        }
        if(!td||!tt){
            return true;
        }
        return (parseFloat(ad+at)-parseFloat(td+tt))>0;
    },
    startMainAutoUpdate:function(){
        var self=this;
        if (this.mainIntervalObj == null) {
            this.mainIntervalObj = setInterval(function(){
                if (!$.isEmptyObject(self.mainTickers)) {
                var arr = [];
                for (var mainKey in self.mainTickers) {
                    arr.push(mainKey.split(":")[0] + ".1." + mainKey.split(":")[1]);
                }
                self.quoteMainTickers(arr.join(","));
                }
            }, this.mianIntervalTime);
        }
    },
    stopMainAutoUpdate:function(){
        if(this.mainIntervalObj!=null){
            clearInterval(this.mainIntervalObj);
            this.mainIntervalObj=null;
        }
    },
    _quoteTickers:function(para,callback){
        $.post(PULL_Path+this.config.quoteURL+"?t="+new Date().getTime(),para, function(o){
            if (o == null || o == '') {
                return;
            }else {
                o = $.evalJSON(o);
                if (o.errorcode) {
                    return;
                }else{
                    callback(o);
                }
            }
        });
    },
    quoteMainTickers:function(mainTickers){
        var self=this;
        var para={
            tickers:mainTickers
        };
        if(this.visibleTokens.length!=0){
            para["tokens"]=this.visibleTokens.join(",");//.replace(/D/g,"")
        }
        this._quoteTickers(para,function(o){
            self._mainCallback(o);
        });
    },
    startSubAutoUpdate:function(){
        var self=this;
        if (this.subIntervalObj == null) {
            this.subIntervalObj = setInterval(function(){
                if (!$.isEmptyObject(self.subTickers)) {
                    var arr = [];
                    for (var subKey in self.subTickers) {
                        arr.push(subKey.split(":")[0] + ".1." + subKey.split(":")[1]);
                    }
                    self._quoteTickers({
                        tickers: arr.join(",")
                    }, function(o){
                        self._subCallback(o);
                    });
                }
            }, this.mianIntervalTime);
        }
    },
    stopSubAutoUpdate:function(){
        if(this.subIntervalObj!=null){
            clearInterval(this.subIntervalObj);
            this.subIntervalObj=null;
        }
    },
    /*batchSubscribeSubTickers:function(tickers){
        var len=tickers.length;
        if(len==0){
            return;
        }
        var symbol,exch,list=[],arr;
        for(var i=0;i<len;i++){
            symbol=tickers[i].replace(".","/");
            arr=symbol.split(":");
            if(arr.length>1){
                symbol=arr[1];
                exch=this._getTenforeExch(arr[0]);
            }else{
                symbol=arr[0];
                exch="126";
            }
            symbol=symbol.toUpperCase();
            list.push({gkey:exch+":"+symbol,paraList:[{sourceType:"D",serviceName:exch,itemName:"1"+push.subSeparator+symbol+push.subSeparator+"-1"}],isSubscribeLevelII:false});
        }
        if(typeof push!='undefined'&&typeof push.proxy!='undefined'){
            push.proxy.batchSubscribe(list);
        }
    },
    _getTenforeExch:function(MICCode){
        for(var exch in this.MICMap){
            if(MICCode==this.MICMap[exch]){
                return exch;
            }
        }
    },*/
    createListViews:function(container,exch,tokens,columns){
        var self=this;
        for(var i=0,l=tokens.length;i<l;i++){
            if(typeof this.listViews[exch]=='undefined') {
                this.listViews[exch] = {};
            }
            this.listViews[exch][tokens[i]]=new QS_ListView(container,columns,$.extend(true,{title:this.tokens[tokens[i]]},this.config),{
                onCellClick:function(e,cell,row){
                    if(!self.config.clickable||(cell.key!='Symbol'&&cell.key!='Name')){
                        return;
                    }
                    var gkey=row.data["gkey"];
                    var d=self.subTickers[gkey];
                    var miccode,mssymbol,symbol;
                    if(d){
                        symbol=d["Gid"];
                    }
                    var url="api.jsp?instid=QUEST&module=research";
                    if(symbol){
                       url+="&symbol="+symbol;   
                    }else{
                        return;
                    }
                    if(typeof self.callback.customTickerClick=='function'){
                        self.callback.customTickerClick(symbol,url);
                    }else{
                        window.open(url,"glaPopWindow","toolbar=no,directories=no,status=no,scrollbars=yes,resizable=yes,menubar=no,width=800,height=600");
                    }
                }
            });
        }
    },
    createListViews1:function(container,exch){
        var self=this;
         for(var token in this.tokens){
            if(typeof this.listViews[exch]=='undefined') {
                this.listViews[exch] = {};
            }
            this.listViews[exch][token]=new QS_ListView(container,this.columns,$.extend(true,{title:this.tokens[token]},this.config),{
                onCellClick:function(e,cell,row){
                    if(!self.config.clickable||(cell.key!='Symbol'&&cell.key!='Name')){
                        return;
                    }
                    var gkey=row.data["gkey"];
                    var d=self.subTickers[gkey];
                    var miccode,mssymbol,symbol;
                    if(d){
                        symbol=d["Gid"];
//                        miccode=d["MIC-CODE"];
//                        mssymbol=d["MSSymbol"];
                    }
//                    if(miccode&&miccode!=''&&mssymbol&&mssymbol!=''){
//                        symbol=miccode+":"+mssymbol;
//                    }
                    var url="api.jsp?instid=QUEST&module=research";
                    if(symbol){
                       url+="&symbol="+symbol;   
                    }else{
                        return;
                       //url+="&glaError=1";
                    }
                    if(typeof self.callback.customTickerClick=='function'){
                        self.callback.customTickerClick(symbol,url);
                    }else{
                        window.open(url,"glaPopWindow","toolbar=no,directories=no,status=no,scrollbars=yes,resizable=yes,menubar=no,width=800,height=600");
                    }
                }
            });
        }
    },
    /*updateData: function(gkey, aData){
        if (gkey.substring(gkey.length - this.staticTicker.length, gkey.length) == this.staticTicker) {
            this.batchReBindListView(gkey, aData);
            
        }else {
            for(var k in this.listViews){
                for (var t in this.listViews[k]) {
                    this.listViews[k][t].updateData(gkey, aData);
                }
            }
        }
    },*/
    changeOutSize:function(w,h){
        var parent = this.el.parent();
        w = w>0?w:parent.width();
        h = h>0?h:parent.height();
        var size={};
        size.width=w;
        if(this.config.fixHeight){
            size.height=h;
        }
        this.el.css(size);
        if (this.scrollPN != null) {
            this.scrollPN.reSize(null, h - this.headHeight);
        }
        for(var k in this.listViews){
            for (var t in this.listViews[k]) {
                this.listViews[k][t].grid.ellipsisDom();
            }
        }
        this.onHeightChange(this.el.height());
    },
    onHeightChange:function(height){
        if (!this.loaded) {
            this.lastCallbackHeight = height;
            this.loaded = true;
            if (typeof this.callback.onLoad == 'function') {
                this.callback.onLoad({
                    component: 'gla',
                    height: height,
                    minWidth:this.minWidth
                });
            }
        }else {
            if (this.lastCallbackHeight != height) {
                this.lastCallbackHeight = height;
                if (typeof this.callback.onHeightChange == 'function') {
                    this.callback.onHeightChange({
                        height: this.lastCallbackHeight,
                        component: 'gla'
                    });
                }
            }
        }
    },
    batchReBindListView:function(gkey,aData){
        var self=this;
        var exch=gkey.split(":")[0];
        for(var token in this.tokens){
            if(aData[token]){
                var listView = this.listViews[exch][token];
                if (listView) {
                    this.createGridData(gkey, token, listView);
                };
            }
        }
        this.changeOutSize(this.config.width,this.config.height);
    },
    createGridData:function(gkey,id,listView){
        var self =this,
            exch=gkey.split(":")[0],
            key,
            needCheckTickers={},
            gridData=[],
            list=[],
            aDataMap={};

        if(gData&&gData[gkey]&&gData[gkey][id]){
             var t10=gData[gkey][id].split(",");
             var len=t10.length>this.config.maxCount?this.config.maxCount:t10.length;
             for(var j=0,len=len;j<len;j++){
                key=exch+":"+t10[j];
                //needSubTickers.push(key);
                gridData.push({
                    gkey:key,
                    Symbol:t10[j]
                });
                if (!needCheckTickers[key]) {
                    needCheckTickers[key]=true;
                    list.push({
                        gkey: key,
                        paraList: [{
                            sourceType: "D",
                            serviceName: exch,
                            itemName: "1" +push.subSeparator+ t10[j]+push.subSeparator+ "-1"
                        }],
                        isSubscribeLevelII: false
                    });
                }
                if (this.getDataFromGData(key)) {
                    aDataMap[key] = this.getDataFromGData(key);
                }
             }     
        }
        listView.reBindData(gridData);
        for(var key in aDataMap){
            listView.updateData(key,aDataMap[key]);
        }
        
        if(typeof push!='undefined'&&typeof push.proxy!='undefined'){
            push.proxy.batchSubscribe(list);
        }
    },
    getDataFromGData:function(gkey){
        var d={},field;
        for(var i=0,l=this.columns.length;i<l;i++){
            field=this.columns[i].dataIndex;
            if(field=='Symbol'||field=='UpDown'||this.columns[i].hide){
                continue;
            }
            var mq=push.proxy.getMarketQuoteData(gkey,field);
            if(typeof mq=='undefined'){
                continue;
            }
            d[field]=mq;
        }
        return d;
    },
    genExchange:function(exch){
        return exch<126?126:exch;
    }
};

QS_MarketTabedGLA=function(container,config,callback){
    this.el=null;
    this.container = typeof container=='string'? $(container):container;
    $.extend(true,this.config,{
        tokens:"D1902,D1900,D1903,D1901,D1904",
        hideTitle:true
    },config);
    $.extend(true,this.callback,callback);
    if(this.config.customColumns&&this.config.customColumns.length>0){
        this.customColumns=this.config.customColumns;
    }
    this.headHeight=0;
    this.tabmenu=null;
    this.scrollPN=null;
};
QS_MarketTabedGLA.prototype=$.extend(true,{},QS_BaseGainerLoserActive,{
    init:function(){
        this.el=$(this.html).addClass('qs-gla-tab').appendTo(this.container);
        var headEl=this.el.find('.hd');
        this._createTab(headEl);
        if (this.config.fixHeight) {
            this.scrollPN = new Util.ScrollPanel(this.el.find('.data'));
        }
        this.headHeight=headEl.outerHeight(true);
    },
    changeExchange:function(exchange){
        this.config.exchange=exchange;
        this.tabmenu.currentTab = null;
        this.tabmenu.changeTabById(this.visibleTokens[0],true);
    },
    _genTokensData:function(){
        var data=[],at=this.config.tokens.split(",");
        for(var i=0,l=at.length;i<l;i++){
            data.push({
                id: at[i],
                txt: this.tokens[at[i]],
                closable: false
            });
        }
        return data;
    },
    _createTab:function(container){
        var self = this;
        this.tabmenu = new Util.TabMenu(container, this._genTokensData(), {
            onActive: function(tab){
                self.visibleTokens=[tab.id];
                self.subscribeNewExch(tab.id);
            },
            onDeActive: function(tab){
                self.empty(tab.id);
            }
        }, {
            tabsList: false,
            activeAtInit: true,
            autoSlideToActiveTab:true
        });
    },
    subscribeNewExch:function(token){
        var exch=Math.floor(this.config.exchange);
        this.createListViews(this.el.find('.data'),this.genExchange(exch),[token],this.customColumns);
        var mainKey=exch+":"+this.MSTATSTickerMap[this.config.exchange];
        var mainTickers=exch+".1."+this.MSTATSTickerMap[this.config.exchange];
        this.mainTickers[mainKey]={};
        this.quoteMainTickers(mainTickers);
        this.startMainAutoUpdate();
        this.startSubAutoUpdate();
    },
    empty:function(token){
        var exch=this.genExchange(Math.floor(this.config.exchange));
        this.mainTickers={};
        this.subTickers={};
        this.stopMainAutoUpdate();
        this.stopSubAutoUpdate();
        this.el.find('.data')[0].innerHTML='';
        if (typeof token == 'undefined') {
            this.listViews={};
        }else {
            delete this.listViews[exch][token];
        }
    }
});

QS_MarketListGLA=function(container,config,callback){
    this.el=null;
    this.container = typeof container=='string'? $(container):container;
    $.extend(true,this.config,{
        showCountryTab:false,
        showExchangeDDL:false,
        showHead:false,
        tokens:"D1902,D1900,D1903,D1901,D1904"
    },config);
    $.extend(true,this.callback,callback);
    if(this.config.customColumns&&this.config.customColumns.length>0){
        this.customColumns=this.config.customColumns;
    }
    this.headHeight=0;
    this.headEl=null;
    this.dataEl=null;
};
QS_MarketListGLA.prototype=$.extend(true,{},QS_BaseGainerLoserActive,{
    init:function(){
        this.el=$(this.html).appendTo(this.container);
        this.headEl=this.el.find('.hd');
        this.dataEl=this.el.find('.bd .data');
        if(!this.config.showHead){//hide the head
            this.headEl.hide();
        }else{
            if(this.config.showCountryTab){
                this._createCountryTabMenu(this.headEl);
            }
        }
        
        if (this.config.fixHeight) {
            this.scrollPN = new Util.ScrollPanel(this.dataEl,{
                 delayRun: false
            });
        }
        this.reCreateListViews();
        this.headHeight=this.headEl.outerHeight(true);
    },
    _createExchangeDDL:function(container,exch){
        var self=this;
        var data=[];
        var f_exch=this.genExchange(exch);
        if(f_exch=='126'){
            data=[{txt:"NYSE",val:"14"},
            {txt:"NASDAQ",val:"19"},
            {txt:"AMEX",val:"1"},
            {txt:"ARCA",val:"16"}
            ];
        }else if(f_exch=='127'){
            data=[{txt:"Toronto",val:"127.1"},{
                txt: "Venture",val: "127.2"
            }];
        }
        var exchangeDDL=new Util.DropDownList(container,function(t, v){
            self.emptyTickersByExch(this.exch);
            self.reCreateListViewsByExch(this.exch,v);
            this.exch=Math.floor(v);
        },data,{
            actionAtInit:false
        });
        exchangeDDL.exch=exch;
    },
    _createCountryTabMenu:function(container){
        var self=this;
        var tabData=[{
            txt: 'Canada',
            closable: false,
            id: '127'
        }, {
            txt: 'USA',
            closable: false,
            id: '126'
        }];
        var tabmenu = new Util.TabMenu(container, tabData, {
            onActive: function(tab){
                self.config.exchange=tab.id;
                self.emptyBody();
                self.reCreateListViews();
            },
            onDeActive: function(tab){
            }
        }, {
            tabsList: false,
            isExcuteCallbackAtInit: false
        });
    },
    reCreateListViews:function(){
        var mts=[];
        var selectExch=this.config.exchange.split(",");
        var l=selectExch.length,width=100/l;// cal the width
        this.visibleTokens=this.config.tokens.split(",");
        for(var i=0;i<l;i++){
            var exch=Math.floor(selectExch[i]);
            var mainKey=exch+":"+this.MSTATSTickerMap[selectExch[i]];
            this.mainTickers[mainKey]={};
            var mainTickers=exch+".1."+this.MSTATSTickerMap[selectExch[i]];
            mts.push(mainTickers);
            f_exch=this.genExchange(exch);
            if(this.config.showHead&&this.config.showExchangeDDL){//hide the head
                var headEl=$('<div class="bd-column-title" style="width:'+width+'%"><span class="country-name label">' + this.countryMap[f_exch] +'</span><span class="exchange"><span class="label">Exchange:</span><span class="exchange-ddl"></span></span></div>').appendTo(this.headEl);
                this._createExchangeDDL(headEl.find('.exchange-ddl'),exch);
            }
            var container=$('<div class="bd-column" style="width:'+width+'%" exch="'+exch+'"></div>').appendTo(this.dataEl);
            this.createListViews(container,f_exch,this.visibleTokens,this.customColumns);
        }
        this.quoteMainTickers(mts.join(","));
        this.startMainAutoUpdate();
        this.startSubAutoUpdate();
    },
    reCreateListViewsByExch:function(oExch,exch){
        var exch1=Math.floor(exch);
        var f_oExch=this.genExchange(oExch);
        var f_exch=this.genExchange(exch1);
        if(this.listViews[f_oExch]){//remove listview onjects
            delete this.listViews[f_oExch];
        }   
        var container=this.el.find('.bd div[exch='+oExch+']');
        container[0].innerHTML='';
        container.attr('exch',f_exch);
        var stTicker=this.MSTATSTickerMap[exch];
        this.createListViews(container,f_exch,this.visibleTokens,this.customColumns);
        var mainKey=exch1+":"+stTicker
        var t=exch1+".1."+stTicker;
        this.mainTickers[mainKey]={};
        this.quoteMainTickers(t);
    },
    emptyTickersByExch:function(exch){
        var f_exch=this.genExchange(exch);
        for(var m in this.mainTickers){// remove main ticker
            if(m.split(":")[0]==exch){
                delete this.mainTickers[m];
                break;
            }
        }
        for(var s in this.subTickers){// remove sub tickers
            if(s.split(":")[0]==f_exch){
                delete this.subTickers[s];
            }
        }
    },
    emptyBody:function(){
        this.mainTickers={};
        this.subTickers={};
        this.stopMainAutoUpdate();
        this.stopSubAutoUpdate();
        this.dataEl[0].innerHTML='';
        this.listView={};
    },
    empty:function(){
        this.headEl[0].innerHTML='';
        this.emptyBody();
    },
    changeExchange:function(exchange){
        var oldExch=this.config.exchange;
        this.config.exchange=exchange;
        this.empty();
        this.reCreateListViews();
    }
});

QS_MarketGLA=function(container,config,callback){
    this.container = typeof container=='string'? $(container):container;
    this.config={
        type:'tab',
        country:'USA',
        exchange:'126'
    };
    this.callback={};
    if(config){
        $.extend(this.config,config);
    }
    if(callback){
        $.extend(this.callback,callback);
    }
    this.glaWidget=null;
};
QS_MarketGLA.prototype={
    init:function(){
        if(this.config.type=='tab'){
            this.glaWidget=new QS_MarketTabedGLA(this.container,this.config);
            this.glaWidget.init();
        }else if(this.config.type=='list'){
            this.glaWidget=new QS_MarketListGLA(this.container,this.config);
            this.glaWidget.init();
        }
    },
    changeOutSize:function(w,h){
        if(this.glaWidget!=null){
            this.glaWidget.changeOutSize(w,h);
        }
    },
    changeExchange:function(country,exchange){
        this.config.country=country;
        if(this.config.exchange!=exchange){
            this.glaWidget.empty();
            this.config.exchange=exchange;
            this.glaWidget.changeExchange(exchange);
        }
    },
    empty:function(){
       this.container[0].innerHTML='';
       this.glaWidget.empty();
       this.glaWidget=null;
    },
    changeType:function(type){
        this.config.type=type;
        this.empty();
        this.init();
    },
	saveConfig:function(){
		return {
			country:this.config.country,
			exchange:this.config.exchange,
			type:this.config.type
		}
	}
};